<!DOCTYPE html>
<html>
  <head>
    <style>
      html,
      body,
      #root {
        margin: 0;
        padding: 0;
        width: 100%;
        height: 100%;
      }
      body {
        font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
          Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
      }
    </style>
    <script src="https://cdn.jsdelivr.net/npm/@babel/standalone/babel.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@rollup/browser/dist/rollup.browser.min.js"></script>
    <script>
      (() => {
        let scriptEls = [];

        let jsxCode = "";
        async function handle_message(ev) {
          let { action, cmd_id, code } = ev.data;
          const send_message = (payload) =>
            parent.postMessage({ ...payload }, ev.origin);
          const send_reply = (payload) => send_message({ ...payload, cmd_id });
          const send_ok = () => send_reply({ action: "cmd_ok" });
          const send_error = (message, stack) =>
            send_reply({ action: "cmd_error", message, stack });
          if (action === "eval") {
            try {
              if (scriptEls.length) {
                scriptEls.forEach((el) => {
                  document.head.removeChild(el);
                });
                scriptEls.length = 0;
              }

              let { script: scripts } = ev.data.args;
              if (typeof scripts === "string") scripts = [scripts];

              for (const script of scripts) {
                const scriptEl = document.createElement("script");
                // scriptEl.setAttribute('type', 'module')
                // send ok in the module script to ensure sequential evaluation
                // of multiple proxy.eval() calls
                const done = new Promise((resolve) => {
                  window.__next__ = resolve;
                });
                scriptEl.innerHTML = script + `\nwindow.__next__()`;
                document.head.appendChild(scriptEl);
                scriptEl.onerror = (err) => send_error(err.message, err.stack);
                scriptEls.push(scriptEl);
                await done;
              }
              send_ok();
            } catch (e) {
              send_error(e.message, e.stack);
            }
          } else if (action === "render") {
            const modules = {
              "main.js": `
    import React from 'react';
    import ReactDom from 'react-dom';
    import Page from './Page.js';

    ReactDOM.render(<Page />, document.getElementById('root'));
    `,
              "./Page.js": code[0],
            };
            // 编译 umd
            rollup
              .rollup({
                input: "main.js",
                external: ["react", "react-dom"],
                output: {
                  format: "umd",
                  name: "MyBundle",
                  globals: {
                    react: "windiw.React",
                    "react-dom": "window.ReactDom",
                  },
                  strict: true,
                },
                plugins: [
                  {
                    name: "loader",
                    resolveId(source, importer) {
                      if (modules.hasOwnProperty(source)) {
                        return source || "";
                      } else {
                        return false;
                      }
                    },
                    load(id) {
                      if (modules.hasOwnProperty(id)) {
                        return Babel.transform(modules[id], {
                          plugins: [["transform-react-jsx"]],
                        }).code;
                        return modules[id] || "";
                      } else {
                        return false;
                      }
                    },
                  },
                ],
              })
              .then((bundle) =>
                bundle.generate({
                  format: "iife",
                  globals: {
                    react: "window.React",
                    "react-dom": "window.ReactDom",
                    antd: "window.antd",
                  },
                })
              )
              .then((res) => {
                return res.output[0].code;
              })
              .then((code) => {
                jsxCode = code;
                const scriptTag = document.createElement("script");
                scriptTag.id = "render-script";
                scriptTag.innerHTML = jsxCode;
                const originialScriptTag =
                  document.getElementById("render-script");
                // 如果有的话就替换渲染脚本
                if (originialScriptTag) {
                  originialScriptTag.remove();
                } 
                document.body.appendChild(scriptTag);

              })
              .catch((e) => {
                console.log(e, "error");
              });
          }
        }

        window.addEventListener("message", handle_message, false);
        document.documentElement.addEventListener("click", (event) => {
          parent.postMessage({ action: "click", value: undefined }, "*");
        });
        window.onerror = function (msg, url, lineNo, columnNo, error) {
          if (msg.includes("module specifier “vue”")) {
            // firefox only error, ignore
            return false;
          }
          try {
            parent.postMessage({ action: "error", value: error }, "*");
          } catch (e) {
            parent.postMessage({ action: "error", value: msg }, "*");
          }
        };

        window.addEventListener("unhandledrejection", (event) => {
          if (event.reason.message.includes("Cross-origin")) {
            event.preventDefault();
            return;
          }
          try {
            parent.postMessage(
              { action: "unhandledrejection", value: event.reason },
              "*"
            );
          } catch (e) {
            parent.postMessage(
              { action: "unhandledrejection", value: event.reason.message },
              "*"
            );
          }
        });

        let previous = { level: null, args: null };
      })();
    </script>
  </head>

  <body>
    <!-- links -->
    <div id="root"></div>
    <!-- scripts -->

    <script id="render-jsx"></script>
  </body>
</html>
